package com.example.book_recommend.controller;

import com.example.book_recommend.dao.RoleMapper;
import com.example.book_recommend.dao.UserRoleMapper;
import com.example.book_recommend.entity.SysToken;
import com.example.book_recommend.entity.User;
import com.example.book_recommend.entity.UserRole;
import com.example.book_recommend.entity.UserRoleKey;
import com.example.book_recommend.pojo.storeInfo.MyPageSearch;
import com.example.book_recommend.pojo.userInfo.*;
import com.example.book_recommend.pojo.VueResultInfo;
import com.example.book_recommend.service.RoleService;
import com.example.book_recommend.service.UserRoleService;
import com.example.book_recommend.service.UserService;
import com.example.book_recommend.service.impl.ShiroServiceImpl;
import com.example.book_recommend.service.impl.UserRoleServiceImpl;
import com.example.book_recommend.service.impl.UserServiceImpl;
import com.example.book_recommend.utils.ResultFactory;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
//import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.subject.Subject;
import org.assertj.core.internal.Digests;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import javax.validation.Valid;
import java.io.IOException;
import java.util.*;

@RestController
@EnableAutoConfiguration
@CrossOrigin
@RequestMapping()
@EnableSwagger2
public class UserController {
    @Autowired
    UserService userService;

    @Autowired
    ShiroServiceImpl shiroService;

    @Autowired
    UserRoleMapper userRoleMapper;

    @Autowired
    UserRoleServiceImpl userRoleService;

    /**
     * 登录控制器，前后端分离用的不同协议和端口，所以需要加入@CrossOrigin支持跨域。
     * 给VueLoginInfoVo对象加入@Valid注解，并在参数中加入BindingResult来获取错误信息。
     * 在逻辑处理中我们判断BindingResult知否含有错误信息，如果有错误信息，则直接返回错误信息。
     */
    @RequestMapping(value = "/login", method = RequestMethod.POST, produces = "application/json; charset=UTF-8")
    @ApiOperation(value = "用户登录", notes = "用户登录，必要字段为用户名和密码")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "username", defaultValue = "test03", required = true, paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "password", defaultValue = "e10adc3949ba59abbe56e057f20f883e", required = true, paramType = "query", dataType = "String")
    })
    public VueResultInfo userLogin(@RequestBody @Valid VueLoginInfo loginInfo, BindingResult bindingResult) throws IOException, JSONException {
        VueResultInfo vueResultInfo = new VueResultInfo(-1,"",null);
        if (bindingResult.hasErrors()) {
            String message = String.format("参数错误，详细信息[%s]。", Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage());
            vueResultInfo = ResultFactory.buildFailResult(message);
            return vueResultInfo;
        }

        String username=loginInfo.getUsername();
        String password=loginInfo.getPassword();
        if(userService.passwordVerify(password, username)){
            vueResultInfo.setCode(0);
            vueResultInfo.setMessage("登陆成功");
            User user=userService.findUserByUsername(username);
            Map<String, Object> result = shiroService.createToken(user.getUserId());
            String token = (String) result.get("token");
//            vueResultInfo.setData(token);
//            JSONObject res = new JSONObject();
//            res.put("token",token);
            boolean isAdmin = false;
            if(userRoleMapper.selectByPrimaryKey(new UserRoleKey(user.getUserId(),0))!=null){
                isAdmin = true;
            }
            VueLoginResultInfo res=new VueLoginResultInfo(token,user,isAdmin);
            vueResultInfo.setData(res);
        }else{
            vueResultInfo.setCode(1);
            vueResultInfo.setMessage("登陆失败");
        }

        return vueResultInfo;
    }

    @RequestMapping(value = "/register", method = RequestMethod.POST, produces = "application/json; charset=UTF-8")
    @ApiOperation(value = "用户注册", notes = "用户注册，必要字段为用户名和密码")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "password", value = "this_is_password", required = true, paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "username", value = "this_is_username", required = true, paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "email", value = "this_is_email", required = true, paramType = "query", dataType = "String")
    })
    public VueResultInfo userRegister(@RequestBody @Valid VueRegisterInfo registerInfo, BindingResult bindingResult) throws IOException {
        VueResultInfo vueResultInfo = new VueResultInfo(-1,"",null);
        if (bindingResult.hasErrors()) {
            String message = String.format("参数错误，详细信息[%s]。", Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage());
            vueResultInfo = ResultFactory.buildFailResult(message);
            return vueResultInfo;
        }

        String username=registerInfo.getUsername();
        String email=registerInfo.getEmail();
        String password = registerInfo.getPassword();

        if(userService.findUserByUsername(username)!=null){
            vueResultInfo.setCode(1);
            vueResultInfo.setMessage("用户名已存在");
            return vueResultInfo;
        }

        if(userService.findUserByUsername(username)==null){
            Date date = new Date();

            vueResultInfo.setCode(0);
            vueResultInfo.setMessage("注册成功");
            User user = new User();
            user.setPassword(password);
            user.setUsername(username);
            user.setEmail(email);
            userService.userRegister(user);
            user = userService.findUserByUsername(username);

            //授予权限，默认普通用户
            userRoleService.add(new UserRole(user.getUserId(), 1, date, date));

            Map<String, Object> result = shiroService.createToken(user.getUserId());
            String token = (String) result.get("token");

            boolean isAdmin = false;
            if(userRoleMapper.selectByPrimaryKey(new UserRoleKey(user.getUserId(),1))!=null){
                isAdmin = true;
            }
            VueLoginResultInfo res=new VueLoginResultInfo(token,user,isAdmin);
            vueResultInfo.setData(res);
        }else{
            vueResultInfo.setCode(1);
            vueResultInfo.setMessage("注册失败，并且不是用户名重复的原因");
        }

        return vueResultInfo;
    }

    @RequestMapping(value = "/changeInfo", method = RequestMethod.POST, produces = "application/json; charset=UTF-8")
    @ApiOperation(value = "用户更改角色信息", notes = "用户注册，必要字段为用户名和密码")
    public VueResultInfo userChangeInfo(@RequestBody @Valid User user, BindingResult bindingResult, @RequestHeader("token") String token) throws IOException{
        VueResultInfo vueResultInfo=new VueResultInfo(1,"更改失败哈哈哈气不气",null);
        Integer userId = user.getUserId();
//        System.out.print(token);
        SysToken sysToken = shiroService.findByToken(token);
        Integer tokenUserId = sysToken.getUserId();
        if((int)tokenUserId!=(int)userId){
            vueResultInfo.setMessage("你小子拿着别人的token就来改你自己的信息了？拒绝！");
        }
        String username = user.getUsername();
        User userFind = userService.findUserByUsername(username);
        if(userFind!=null && (int)userFind.getUserId()!=(int)tokenUserId){
            vueResultInfo.setCode(1);
            vueResultInfo.setMessage("用户名已存在");
            return vueResultInfo;
        }
        userService.changeUserInfo(user);
        vueResultInfo.setCode(0);
        vueResultInfo.setMessage("更改成功");
        return vueResultInfo;
    }

    @RequestMapping("/viewOrders")
    @ApiOperation(value = "查看个人所有订单", notes = "invokePost说明", httpMethod = "POST")
    public VueResultInfo viewOrders(@RequestBody VueCartInfo vueCartInfo, BindingResult bindingResult){
        return ResultFactory.buildSuccessResult(userService.viewOrders(vueCartInfo.getUid()));
    }

    @RequestMapping("/viewDetailedOrders")
    @ApiOperation(value = "查看订单详情", notes = "invokePost说明", httpMethod = "POST")
    public VueResultInfo viewDetailedOrders(@RequestBody VueOrderIfo vueOrderIfo, BindingResult bindingResult){
        return ResultFactory.buildSuccessResult(userService.viewDetailedOrders(vueOrderIfo.getOrderId()));
    }

    @RequestMapping("/api/dataInfo/getBookTypeNum")
    @ApiOperation(value = "获取图书类型数目", notes = "invokePost说明", httpMethod = "POST")
    public VueResultInfo getBookTypeNum() {
        ArrayList<HashMap> returnList = new ArrayList<>();
        returnList = userService.getBookTypeNum();
        return ResultFactory.buildSuccessResult(returnList);

    }

    @RequestMapping("/api/dataInfo/getAgeScopeNum")
    @ApiOperation(value = "获取年龄分布数目", notes = "invokePost说明", httpMethod = "POST")
    public VueResultInfo getAgeScopeNum() {
        ArrayList<HashMap> returnList = new ArrayList<>();
        returnList = userService.getAgeScopeNum();
        return ResultFactory.buildSuccessResult(returnList);

    }

    @RequestMapping("/getUserInfo")
    @ApiOperation(value = "获取用户所有信息", notes = "invokePost说明", httpMethod = "POST")
    public VueResultInfo getUserInfo(@RequestBody VueCartInfo vueCartInfo){
        return ResultFactory.buildSuccessResult(userService.getUserInfo(vueCartInfo.getUid()));
    }

    @RequestMapping("/changePassword")
    @ApiOperation(value = "获取用户所有信息", notes = "invokePost说明", httpMethod = "POST")
    public VueResultInfo changePassword(@RequestBody VueUserInfo vueUserInfo){
        return ResultFactory.buildSuccessResult(userService.changePassword(vueUserInfo.getUid(),vueUserInfo.getPassword()));
    }

    @RequestMapping("/recommend/1")
    @ApiOperation(value = "推荐算法1", notes = "invokePost说明", httpMethod = "POST")
    public VueResultInfo recommend1(@RequestBody MyPageSearch myPageSearch){
        Long bookId = Long.valueOf(myPageSearch.getBookId());
        Integer page = myPageSearch.getPage();
        Integer size = myPageSearch.getSize();
        return ResultFactory.buildSuccessResult(userService.recommend1(bookId, page, size));
    }

    @RequestMapping("/recommend/2")
    @ApiOperation(value = "推荐算法2", notes = "invokePost说明", httpMethod = "POST")
    public VueResultInfo recommend2(@RequestBody MyPageSearch myPageSearch){
        Long bookId = Long.valueOf(myPageSearch.getBookId());
        Integer page = myPageSearch.getPage();
        Integer size = myPageSearch.getSize();
        return ResultFactory.buildSuccessResult(userService.recommend2(bookId, page, size));
    }

    @RequestMapping("/recommend/jiamaoweilie")
    @ApiOperation(value = "假冒伪劣推荐算法", notes = "invokePost说明", httpMethod = "POST")
    public VueResultInfo recommendFake(@RequestBody MyPageSearch myPageSearch){
        int uid = myPageSearch.getUid();
        Integer page = myPageSearch.getPage();
        Integer size = myPageSearch.getSize();
        return ResultFactory.buildSuccessResult(userService.recommendFake(uid, page, size));
    }
}

